package com.linkdood.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linkdood.app.component.QuartzJobComponent;
import com.linkdood.app.constants.ErrorCode;
import com.linkdood.app.domain.ScheduleTask;
import com.linkdood.app.dto.ScheduleTaskDTO;
import com.linkdood.app.enums.TaskStatusEnum;
import com.linkdood.app.exception.GeneralException;
import com.linkdood.app.mapper.ScheduleTaskMapper;
import com.linkdood.app.service.AccountService;
import com.linkdood.app.service.ScheduleTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 定时任务 Service 类
 *
 * @author hycao
 */
@Slf4j
@Service
public class ScheduleTaskServiceImpl extends ServiceImpl<ScheduleTaskMapper, ScheduleTask> implements ScheduleTaskService {

    private final QuartzJobComponent quartzJobComponent;

    private final AccountService accountService;

    public ScheduleTaskServiceImpl(QuartzJobComponent quartzJobComponent, AccountService accountService) {
        this.quartzJobComponent = quartzJobComponent;
        this.accountService = accountService;
    }

    /**
     * 创建定时任务
     *
     * @param task 任务
     * @return 是否创建成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ScheduleTask saveTask(ScheduleTaskDTO task) {
        // 保存数据库
        ScheduleTask scheduleTask = taskDtoToTaskQuartz(task);
        String currentUser = accountService.getCurrentAccountId();
        scheduleTask.setCreateBy(currentUser);
        scheduleTask.setCreateTime(LocalDateTime.now());
        scheduleTask.setJobStatus(TaskStatusEnum.START);
        save(scheduleTask);

        // 启动任务
        startTask(scheduleTask);
        return scheduleTask;
    }

    /**
     * 暂停任务
     */
    @Override
    public ScheduleTask pauseTask(String taskId) {
        ScheduleTask task = getById(taskId);
        quartzJobComponent.pauseJob(task.getJobName() + task.getId(), task.getJobGroupName());
        task.setJobStatus(TaskStatusEnum.PAUSE);
        updateById(task);
        return task;
    }

    /**
     * 恢复任务。
     */
    @Override
    public ScheduleTask resumeTask(String taskId) {
        ScheduleTask task = getById(taskId);
        quartzJobComponent.resumeJob(task.getJobName() + task.getId(), task.getJobGroupName());
        task.setJobStatus(TaskStatusEnum.START);
        updateById(task);
        return task;
    }

    /**
     * 启动任务
     *
     * @param task 任务
     * @return 是否创建成功
     */
    @Override
    public ScheduleTask startTask(ScheduleTask task) {
        try {
            //创建新的定时任务
            String jobClassStr = task.getJobClassName();
            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobClassStr);
            String name = task.getJobName() + task.getId();
            String groupName;
            if (StringUtils.isNotBlank(task.getJobGroupName())) {
                groupName = task.getJobGroupName();
            } else {
                groupName = "Default group";
            }
            String description = task.getDescription();
            String time = task.getCronExpression();

            JobDetail jobDetail = quartzJobComponent.createJobDetail(clazz, name, groupName, description);
            if (jobDetail == null) {
                return new ScheduleTask();
            }
            jobDetail.getJobDataMap().put(ScheduleTask.JOB_KEY, task);
            Trigger trigger = quartzJobComponent.createCronTrigger(jobDetail, time, name, groupName, description);
            if (trigger == null) {
                return new ScheduleTask();
            }
            quartzJobComponent.create(jobDetail, trigger);
            return task;
        } catch (Exception e) {
           throw new GeneralException(ErrorCode.ERROR_SCHEDULE_TASK);
        }
    }

    /**
     * 修改旧的定时任务， 只支持修改定时时间
     *  @param oldTask 旧任务
     * @param task 修改后的任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ScheduleTask modifyTaskCron(ScheduleTask oldTask, ScheduleTaskDTO task) {
        if (oldTask == null || task == null) {
            return new ScheduleTask();
        }
        try {
            String oldName = oldTask.getJobName() + oldTask.getId();
            String oldGroupName = oldTask.getJobGroupName();
            //1、获取旧定时任务，更新定时器
            CronTrigger cronTrigger = quartzJobComponent.getCronTrigger(oldName, oldGroupName);
            CronTriggerImpl cronTrigger1 = (CronTriggerImpl) cronTrigger;
            cronTrigger1.setCronExpression(task.getCronExpression());

            //2、更新定时任务
            quartzJobComponent.reschedule(oldName, oldGroupName, cronTrigger1);

            //3、更新数据库
            ScheduleTask scheduleTask = taskDtoToTaskQuartz(task);
            String currentUser = accountService.getCurrentAccountId();
            scheduleTask.setId(oldTask.getId());
            scheduleTask.setCreateBy(currentUser);
            scheduleTask.setCreateTime(LocalDateTime.now());
            updateById(scheduleTask);

            return scheduleTask;
        } catch (Exception e) {
            throw new GeneralException(ErrorCode.ERROR_SCHEDULE_TASK);
        }
    }

    /**
     * 删除旧的定时任务，创建新的定时任务
     *  @param oldTask 旧任务
     * @param task 修改后的任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ScheduleTask modifyTask(ScheduleTask oldTask, ScheduleTaskDTO task) {
        if (oldTask == null || task == null) {
            return new ScheduleTask();
        }
        try {
            String oldName = oldTask.getJobName() + oldTask.getId();
            String oldGroupName = oldTask.getJobGroupName();
            //1、清除旧的定时任务
            quartzJobComponent.delete(oldName, oldGroupName);
            //2、创建新的定时任务，更新数据库
            ScheduleTask scheduleTask = taskDtoToTaskQuartz(task);
            String currentUser = accountService.getCurrentAccountId();
            if (StringUtils.isNotBlank(task.getJobGroupName())) {
                scheduleTask.setJobGroupName(task.getJobGroupName());
            } else {
                scheduleTask.setJobGroupName("Default group");
            }
            scheduleTask.setId(oldTask.getId());
            scheduleTask.setCreateBy(currentUser);
            scheduleTask.setCreateTime(LocalDateTime.now());
            updateById(scheduleTask);
            startTask(scheduleTask);
            return scheduleTask;
        } catch (Exception e) {
            throw new GeneralException(ErrorCode.ERROR_SCHEDULE_TASK);
        }
    }

    /**
     * 获取任务分页信息
     */
    @Override
    public Page<ScheduleTask> pageTasks(LambdaQueryWrapper<ScheduleTask> queryWrapper, Page<ScheduleTask> page) {
        return baseMapper.selectPage(page, queryWrapper);
    }

    /**
     * 删除任务
     * @param id 任务id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTask(String id) {
        ScheduleTask task = getById(id);
        try {
            quartzJobComponent.delete(task.getJobName() + id, task.getJobGroupName());
        } catch (SchedulerException e) {
            throw new GeneralException(ErrorCode.ERROR_SCHEDULE_TASK);
        }

        this.removeById(id);
    }

    /**
     * DTO 和 实体类 转换类
     * @param scheduleTaskDto 入参DTO
     * @return 实体类
     */
    private ScheduleTask taskDtoToTaskQuartz(ScheduleTaskDTO scheduleTaskDto) {
        ScheduleTask scheduleTask = new ScheduleTask();
        BeanUtils.copyProperties(scheduleTaskDto, scheduleTask);
        return scheduleTask;
    }

}
